package btreegui;

import btreetestat.BTreeController;
import btreetestat.TreeContainer;
import btreetestat.TreeNode;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.*;

/**
 *
 * @author Bart
 */
public class BTreeGUI extends JFrame {

    private ArrayList<JButton> btns;    //Für ButtonController switch case
    private JButton btVerzweigungsgrad;
    private JButton btEinfügen;
    private JButton btSuchen;
    private JButton btRandomEinfügen;
    private JButton btLöschen;
    private JPanel panelButton;
    private JLabel lbÜberschrift;
    private JLabel lbRandMin;
    private JLabel lbRandMax;
    private JLabel lbVerzweigungsgrad;
    private JSpinner jsEinfSuchRand;
    private JSpinner jsVerzweigungsgrad;
    private JSpinner jsRandMin;
    private JSpinner jsRandMax;
    private JSpinner jsLöschen;
    private JTree jTree;
    private JScrollPane jScrollPane;
    private JScrollPane jScrollPaneCanvas;
    private BTreeController bTreeController = null;
    private int depth;
    private GuiTreeNode rootNode;
    private JSplitPane splitPane;
    private JPanel pobj;
    private DrawTree drawTreePanel;
    private JViewport jviewport;
    TreeCellRenderer renderer = new TreeCellRenderer();

    public BTreeGUI() {
        super("B-Tree");

        //Set the frame icon to an image loaded from a file.
        String imgURL = "";
        this.setIconImage(new ImageIcon(imgURL).getImage());

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1280, 800);
        setLocationRelativeTo(null);
        setVisible(true);

        initFrame();
    }

    private void initFrame() {

        //Buttons erzeugen
        btVerzweigungsgrad = new JButton("Neuer Baum");
        btEinfügen = new JButton("Einfügen");
        btSuchen = new JButton("Suchen");
        btRandomEinfügen = new JButton("Zufallszahl(en) einfügen");
        btLöschen = new JButton("Löschen");
        btns = new ArrayList<JButton>();

        btns.add(btVerzweigungsgrad);
        btns.add(btEinfügen);
        btns.add(btSuchen);
        btns.add(btRandomEinfügen);
        btns.add(btLöschen);

        //Labels erzeugen
        lbÜberschrift = new JLabel("B-Tree");
        lbRandMin = new JLabel("min:");
        lbRandMax = new JLabel("max:");
        lbVerzweigungsgrad = new JLabel("Verzweigungsgrad:");

        //JTree  und Scrollkontainer erzeugen
        rootNode = new GuiTreeNode("B-Tree");
        jTree = new JTree(rootNode);
        jTree.setExpandsSelectedPaths(true);
        jTree.setDoubleBuffered(true);
        jTree.setShowsRootHandles(true);
        jTree.setCellRenderer(renderer);
        renderer.setFrame(this);
        jScrollPane = new JScrollPane(jTree);

        drawTreePanel = new DrawTree(this);
        jviewport = new JViewport();
        jviewport.add(drawTreePanel);
        pobj = new JPanel();
        pobj.add(jviewport);
        drawTreePanel.setPreferredSize(new Dimension(1200, 400));
        jScrollPaneCanvas = new JScrollPane(pobj, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jScrollPane, jScrollPaneCanvas);
        splitPane.setOneTouchExpandable(true);
        splitPane.setDividerLocation(180);


        //Spinner erzeugen
        jsEinfSuchRand = new JSpinner(new SpinnerNumberModel(
                0, //Value
                0, //Min
                100000, //Max
                1));    //Step
        jsVerzweigungsgrad = new JSpinner(new SpinnerNumberModel(
                2, //Value
                1, //Min
                100000, //Max
                1));    //Step
        jsRandMin = new JSpinner(new SpinnerNumberModel(
                0, //Value
                0, //Min
                100000, //Max
                1));    //Step
        jsRandMax = new JSpinner(new SpinnerNumberModel(
                100, //Value
                1, //Min
                100000, //Max
                1));    //Step
        jsLöschen = new JSpinner(new SpinnerNumberModel(
                0, //Value
                0, //Min
                100000, //Max
                1));    //Step


        //Gridbaglayout erzeugen und bestücken
        //
        //Panels erzeugen auf einem GridBagLayout
        panelButton = new JPanel();
        panelButton.setLayout(new GridBagLayout());

        GridBagConstraints c;
        // Objekt für Abstände zwischen den GUI-Komponenten.
        Insets set = new Insets(5, 5, 5, 5);

        // Eigenschaften für die Beschriftung "jsVerzweigungsgrad:".
        c = new GridBagConstraints();
        c.insets = set; // Abstände setzen.
        c.gridx = 0; // Position auf X-Achse setzen.
        c.gridy = 0; // Position auf Y-Achse setzen.
        // Setze die Ausbreitung der GUI-Komponente.
        c.fill = GridBagConstraints.HORIZONTAL;
        // Ausrichtung setzen.
        c.anchor = GridBagConstraints.LINE_START;
        //Buttons auf das Panel packen
        panelButton.add(lbVerzweigungsgrad, c);

        // Eigenschaften für die Beschriftung "jsEinfSuchRand:".
        c.gridy = 1; // Position auf Y-Achse setzen.
        //Buttons auf das Panel packen
        panelButton.add(jsEinfSuchRand, c);

        // Eigenschaften für die Beschriftung "jtLöschen:".
        c.gridy = 2; // Position auf Y-Achse setzen.
        //Buttons auf das Panel packen
        panelButton.add(jsLöschen, c);

        // Eigenschaften für die Beschriftung "btVerzweigungsgrad:".
        c = new GridBagConstraints();
        c.insets = set; // Abstände setzen.
        c.gridx = 1; // Position auf X-Achse setzen.
        c.gridy = 0; // Position auf Y-Achse setzen.
        // Setze die Ausbreitung der GUI-Komponente.
        c.fill = GridBagConstraints.HORIZONTAL;
        //Buttons auf das Panel packen
        panelButton.add(jsVerzweigungsgrad, c);

        // Eigenschaften für die Beschriftung "btEinfügen:".
        c.gridy = 1; // Position auf Y-Achse setzen.
        //Buttons auf das Panel packen
        panelButton.add(btEinfügen, c);

        // Eigenschaften für die Beschriftung "btLöschen:".
        c.gridy = 2; // Position auf Y-Achse setzen.
        //Buttons auf das Panel packen
        panelButton.add(btLöschen, c);

        // Eigenschaften für die Beschriftung "btRandomEinfügen:".
        c = new GridBagConstraints();
        c.insets = set; // Abstände setzen.
        c.gridx = 2; // Position auf X-Achse setzen.
        c.gridy = 0; // Position auf Y-Achse setzen.
        // Setze die Ausbreitung der GUI-Komponente.
        c.fill = GridBagConstraints.HORIZONTAL;
        // Ausrichtung setzen.
        c.anchor = GridBagConstraints.LINE_START;
        //Buttons auf das Panel packen
        panelButton.add(btVerzweigungsgrad, c);

        // Eigenschaften für die Beschriftung "btSuchen:".
        c.gridy = 1; // Position auf Y-Achse setzen.
        //Buttons auf das Panel packen
        panelButton.add(btSuchen, c);

        // Eigenschaften für die Beschriftung "btRandomEinfügen:".
        c = new GridBagConstraints();
        c.insets = set; // Abstände setzen.
        c.gridx = 3; // Position auf X-Achse setzen.
        c.gridy = 1; // Position auf Y-Achse setzen.
        // Ausrichtung setzen.
        c.anchor = GridBagConstraints.LINE_START;
        //Buttons auf das Panel packen
        panelButton.add(btRandomEinfügen, c);

        // Eigenschaften für die Beschriftung "btRandomEinfügen:".
        c = new GridBagConstraints();
        c.insets = set; // Abstände setzen.
        c.gridx = 4; // Position auf X-Achse setzen.
        c.gridy = 1; // Position auf Y-Achse setzen.
        // Ausrichtung setzen.
        c.anchor = GridBagConstraints.LINE_START;
        //Buttons auf das Panel packen
        panelButton.add(lbRandMin, c);

        // Eigenschaften für die Beschriftung "btRandomEinfügen:".
        c = new GridBagConstraints();
        c.insets = set; // Abstände setzen.
        c.gridx = 5; // Position auf X-Achse setzen.
        c.gridy = 1; // Position auf Y-Achse setzen.
        // Ausrichtung setzen.
        c.anchor = GridBagConstraints.LINE_START;
        //Buttons auf das Panel packen
        panelButton.add(jsRandMin, c);

        // Eigenschaften für die Beschriftung "btRandomEinfügen:".
        c = new GridBagConstraints();
        c.insets = set; // Abstände setzen.
        c.gridx = 6; // Position auf X-Achse setzen.
        c.gridy = 1; // Position auf Y-Achse setzen.
        // Ausrichtung setzen.
        c.anchor = GridBagConstraints.LINE_START;
        //Buttons auf das Panel packen
        panelButton.add(lbRandMax, c);

        // Eigenschaften für die Beschriftung "btRandomEinfügen:".
        c = new GridBagConstraints();
        c.insets = set; // Abstände setzen.
        c.gridx = 7; // Position auf X-Achse setzen.
        c.gridy = 1; // Position auf Y-Achse setzen.
        // Ausrichtung setzen.
        c.anchor = GridBagConstraints.LINE_START;
        //Buttons auf das Panel packen
        panelButton.add(jsRandMax, c);

        //Listener für Buttons        
        btVerzweigungsgrad.addActionListener(new ButtonController(this));
        btEinfügen.addActionListener(new ButtonController(this));
        btSuchen.addActionListener(new ButtonController(this));
        btRandomEinfügen.addActionListener(new ButtonController(this));
        btLöschen.addActionListener(new ButtonController(this));

        //Überschriftlabel zentrieren und Größe ändern
        lbÜberschrift.setHorizontalAlignment(JLabel.CENTER);
        Font curFont = new Font("Dialog", Font.PLAIN, 24);
        lbÜberschrift.setFont(curFont);

        //Labels auf Frame packen (direkt auf das BorderLayout)
        getContentPane().add(BorderLayout.NORTH, lbÜberschrift);

        //Panels auf Frame packen (das panelButton hat ein GridLayout, dass jetzt in den WestBereich des BorderLayouts kommt)
        getContentPane().add(BorderLayout.SOUTH, panelButton);

        getContentPane().add(BorderLayout.CENTER, splitPane);

        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        BTreeGUI window = new BTreeGUI();
    }

    public void drawTree(TreeContainer container, GuiTreeNode root) {
        boolean markNode = false;
        Collection<TreeNode> values = container.values();
        String output = "";
        for (TreeNode treeNode : values) {
            if (treeNode.getValue().equals(getDrawTreePanel().getSearchValue())) {
                markNode = true;
            }
            output = output + (treeNode.getValue() + "|");
        }
        GuiTreeNode treeNode = new GuiTreeNode(output);
        root.add(treeNode);
        depth++;

        for (TreeNode bTreeNode : values) {
            if (bTreeNode.getChildren() != null) {
                drawTree(bTreeNode.getChildren(), treeNode);
            }
            if (bTreeNode.getBiggerChildren() != null) {
                drawTree(bTreeNode.getBiggerChildren(), treeNode);
            }
        }
        depth--;
        expandTree(jTree);  //Klappt den Baum vollständig auf
        jTree.updateUI();
    }

    private void expandTree(JTree tree) {
        int row = 0;
        while (row < tree.getRowCount()) {
            tree.expandRow(row);
            row++;
        }
    }

    public String getJsVerzweigungsgrad() {
        String value;
        try {
            value = jsVerzweigungsgrad.getValue().toString();
        } catch (NullPointerException ex) {
            value = "";
        }
        return value;
    }

    public String getJsEinfSuchRand() {
        return jsEinfSuchRand.getValue().toString();
    }

    public String getJtLöschen() {
        return jsLöschen.getValue().toString();
    }

    public BTreeController getbTreeController() {
        return bTreeController;
    }

    public void setbTreeController(BTreeController bTreeController) {
        this.bTreeController = bTreeController;
    }

    public GuiTreeNode getRootNode() {
        return rootNode;
    }

    public JTree getjTree() {
        return jTree;
    }

    public void updateTree() {
        rootNode.removeAllChildren();                                   //Explorer Baum
        drawTreePanel.getGuiContainer().getBucket().ClearBucket();      //draw Baum
        drawTree(bTreeController.getStartContainer(), rootNode);        //Explorer Baum
        drawTreePanel.drawTree(bTreeController.getStartContainer());    //draw Baum
        drawTreePanel.updateUI();
    }

    public int getRandMin() {
        return (int) jsRandMin.getValue();
    }

    public int getRandMax() {
        return (int) jsRandMax.getValue();
    }

    public ArrayList<JButton> getBtns() {
        return btns;
    }

    public void setJsEinfSuchRand(int val) {
        this.jsEinfSuchRand.setValue(val);
    }

    public DrawTree getDrawTreePanel() {
        return drawTreePanel;
    }

    public void drawConsTree(TreeContainer container) { // Todo: Konsolenausgabe zum Testen auskommentieren
        Collection<TreeNode> values = container.values();
        String output = "";
        for (TreeNode treeNode : values) {
            output = output + (treeNode.getValue() + "|");
        }
        for (int i = 0; i < depth; i++) {
            System.out.print("\t");
        }
        System.out.println(output);
        depth++;

        for (TreeNode treeNode : values) {
            if (treeNode.getChildren() != null) {
                drawConsTree(treeNode.getChildren());
            }
            if (treeNode.getBiggerChildren() != null) {
                drawConsTree(treeNode.getBiggerChildren());
            }
        }
        depth--;
    }

    public JButton getBtRandomEinfügen() {
        return btRandomEinfügen;
    }
}
